package com.engr.web.interceptor;

import com.engr.annotation.FreeAccess;
import com.engr.consts.AuthConsts;
import com.engr.domain.Member;
import com.engr.domain.MemberLogin;
import com.engr.dto.user.MemberDetails;
import com.engr.repository.member.MemberLoginRepository;
import com.engr.repository.member.MemberRepository;
import com.engr.util.ResponseMessage;
import com.engr.util.ServletUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.Optional;
import java.util.UUID;

@Component
public class ApiRequestInterceptor extends HandlerInterceptorAdapter {

	private static final String TOKEN_HEADER = AuthConsts.TOKEN_HEADER;

	private Logger log = LoggerFactory.getLogger(this.getClass());

	@Autowired
	private MemberLoginRepository memberLoginDao;
	@Autowired
	private MemberRepository memberDao;

	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		// 先设置匿名认证
		SecurityContextHolder.getContext()
				.setAuthentication(new AnonymousAuthenticationToken(UUID.randomUUID().toString(), "anymousUser",
						AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_ANONYMOUS")));
		String uri = ServletUtil.getIpAddr(request);
		// 获取token
		String authToken = request.getHeader(TOKEN_HEADER);
		log.debug("{}", handler instanceof HandlerMethod);
		// 是HandlerMethod类型
		if (handler instanceof HandlerMethod) {
			HandlerMethod handlerMethod = (HandlerMethod) handler;
			FreeAccess freeAccessType = handlerMethod.getBean().getClass().getAnnotation(FreeAccess.class);
			FreeAccess freeAccessMethod = handlerMethod.getMethodAnnotation(FreeAccess.class);
			// Controller类或者其方法被FreeAccess注解,放行
			if (freeAccessType != null || freeAccessMethod != null) {
				// 如果传递了token,也校验token值
				if (StringUtils.isNotBlank(authToken)) {
					Optional<MemberLogin> optional = memberLoginDao.findByToken(authToken);
					// 登录列表存在
					if (optional.isPresent()) {
						MemberLogin memberLogin = optional.get();
						// 且过期时间在现在之后
						if (memberLogin.getExpires().after(new Date())) {
							// 查询会员信息
							Member member = memberDao.findByUsername(memberLogin.getUsername()).get();
							if (member.getLastPasswordReset() == null
									|| memberLogin.getLoginTime().after(member.getLastPasswordReset())) {
								// 期间未发生密码修改或者登录时间在重置密码之后
								// 构建详情
								UserDetails userDetails = MemberDetails.create(member);
								UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
										userDetails, null, userDetails.getAuthorities());
								authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
								// 设置认证
								SecurityContextHolder.getContext().setAuthentication(authentication);
							}
						}
					}
				}
				return true;
			}
		} else {
			// 不是HandlerMethod方法,放行
			return true;
		}
		// 查询登录列表
		Optional<MemberLogin> optional = memberLoginDao.findByToken(authToken);
		// 登录列表存在
		if (optional.isPresent()) {
			MemberLogin memberLogin = optional.get();
			// 且过期时间在现在之后
			if (memberLogin.getExpires().after(new Date())) {
				// 查询会员信息
				Member member = memberDao.findByUsername(memberLogin.getUsername()).get();
				if (member.getLastPasswordReset() != null
						&& memberLogin.getLoginTime().before(member.getLastPasswordReset())) {
					// 期间发生了密码修改，时间已经过期
					String jsonStr = ResponseMessage.error("密码已重置请重新登录").toString();
					response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
					response.getWriter().write(jsonStr);
					response.setStatus(401);
					return false;
				}
				// 构建详情
				UserDetails userDetails = MemberDetails.create(member);
				UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
						userDetails, null, userDetails.getAuthorities());
				authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
				// 设置认证
				SecurityContextHolder.getContext().setAuthentication(authentication);
			} else {
				// 时间已经过期
				String jsonStr = ResponseMessage.error("token已经过期").toString();
				response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
				response.getWriter().write(jsonStr);
				response.setStatus(401);
				return false;
			}
		} else {
			// 登录列表不存在
			String jsonStr = ResponseMessage.error("token无效").toString();
			response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
			response.getWriter().write(jsonStr);
			response.setStatus(401);
			return false;
		}
		log.debug("uri {}", uri);
		return super.preHandle(request, response, handler);
	}
}
